package org.jboss.resteasy.cdi; import org.jboss.resteasy.cdi.i18n.LogMessages; import org.jboss.resteasy.cdi.i18n.Messages; import org.jboss.resteasy.core.InjectorFactoryImpl; import org.jboss.resteasy.core.ValueInjector; import org.jboss.resteasy.spi.ConstructorInjector; import org.jboss.resteasy.spi.InjectorFactory; import org.jboss.resteasy.spi.MethodInjector; import org.jboss.resteasy.spi.PropertyInjector; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.metadata.Parameter; import org.jboss.resteasy.spi.metadata.ResourceClass; import org.jboss.resteasy.spi.metadata.ResourceConstructor; import org.jboss.resteasy.spi.metadata.ResourceLocator; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.CDI; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletContext; import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.util.Map; import java.util.Set; /** * @author Jozef Hartinger */ @SuppressWarnings("rawtypes") public class CdiInjectorFactory implements InjectorFactory { public static final String BEAN_MANAGER_ATTRIBUTE_PREFIX = "org.jboss.weld.environment.servlet."; private BeanManager manager; private InjectorFactory delegate = new InjectorFactoryImpl(); private ResteasyCdiExtension extension; private Map<Class<?>, Type> sessionBeanInterface; public CdiInjectorFactory() { this.manager = lookupBeanManager(); this.extension = lookupResteasyCdiExtension(); sessionBeanInterface = extension.getSessionBeanInterface(); } @Override public ValueInjector createParameterExtractor(Parameter parameter, ResteasyProviderFactory providerFactory) { return delegate.createParameterExtractor(parameter, providerFactory); } @Override public MethodInjector createMethodInjector(ResourceLocator method, ResteasyProviderFactory factory) { return delegate.createMethodInjector(method, factory); } @Override public PropertyInjector createPropertyInjector(ResourceClass resourceClass, ResteasyProviderFactory providerFactory) { return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, providerFactory), resourceClass.getClazz(), sessionBeanInterface, manager); } @Override public ConstructorInjector createConstructor(ResourceConstructor constructor, ResteasyProviderFactory providerFactory) { Class<?> clazz = constructor.getConstructor().getDeclaringClass(); ConstructorInjector injector = cdiConstructor(clazz); if (injector != null) return injector; LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz)); return delegate.createConstructor(constructor, providerFactory); } @Override public ConstructorInjector createConstructor(Constructor constructor, ResteasyProviderFactory factory) { Class<?> clazz = constructor.getDeclaringClass(); ConstructorInjector injector = cdiConstructor(clazz); if (injector != null) return injector; LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz)); return delegate.createConstructor(constructor, factory); } protected ConstructorInjector cdiConstructor(Class<?> clazz) { if (!manager.getBeans(clazz).isEmpty()) { LogMessages.LOGGER.debug(Messages.MESSAGES.usingCdiConstructorInjector(clazz)); return new CdiConstructorInjector(clazz, manager); } if (sessionBeanInterface.containsKey(clazz)) { Type intfc = sessionBeanInterface.get(clazz); LogMessages.LOGGER.debug(Messages.MESSAGES.usingInterfaceForLookup(intfc, clazz)); return new CdiConstructorInjector(intfc, manager); } return null; } public PropertyInjector createPropertyInjector(Class resourceClass, ResteasyProviderFactory factory) { return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, factory), resourceClass, sessionBeanInterface, manager); } public ValueInjector createParameterExtractor(Class injectTargetClass, AccessibleObject injectTarget, Class type, Type genericType, Annotation[] annotations, ResteasyProviderFactory factory) { return delegate.createParameterExtractor(injectTargetClass, injectTarget, type, genericType, annotations, factory); } public ValueInjector createParameterExtractor(Class injectTargetClass, AccessibleObject injectTarget, Class type, Type genericType, Annotation[] annotations, boolean useDefault, ResteasyProviderFactory factory) { return delegate.createParameterExtractor(injectTargetClass, injectTarget, type, genericType, annotations, useDefault, factory); } /** * Do a lookup for BeanManager instance. JNDI and ServletContext is searched. * * @return BeanManager instance */ protected BeanManager lookupBeanManager() { BeanManager beanManager = null; // Do a lookup for BeanManager in JNDI (this is the only *portable* way) beanManager = lookupBeanManagerInJndi("java:comp/BeanManager"); if (beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaComp()); return beanManager; } // Do a lookup for BeanManager at an alternative JNDI location (workaround for WELDINT-19) beanManager = lookupBeanManagerInJndi("java:app/BeanManager"); if (beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaApp()); return beanManager; } beanManager = lookupBeanManagerCDIUtil(); if(beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerViaCDI()); return beanManager; } beanManager = lookupBeanManagerViaServletContext(); if(beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext()); return beanManager; } throw new RuntimeException(Messages.MESSAGES.unableToLookupBeanManager()); } private BeanManager lookupBeanManagerInJndi(String name) { try { InitialContext ctx = new InitialContext(); LogMessages.LOGGER.debug(Messages.MESSAGES.doingALookupForBeanManager(name)); return (BeanManager) ctx.lookup(name); } catch (NamingException e) { LogMessages.LOGGER.debug(Messages.MESSAGES.unableToObtainBeanManager(name)); return null; } catch (NoClassDefFoundError ncdfe) { LogMessages.LOGGER.debug(Messages.MESSAGES.unableToPerformJNDILookups()); return null; } } private static BeanManager lookupBeanManagerViaServletContext() { BeanManager beanManager = null; try { // Look for BeanManager in ServletContext ServletContext servletContext = ResteasyProviderFactory.getContextData(ServletContext.class); // null check for RESTEASY-1009 if (servletContext != null) { beanManager = (BeanManager) servletContext.getAttribute(BEAN_MANAGER_ATTRIBUTE_PREFIX + BeanManager.class.getName()); if (beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext()); return beanManager; } // Look for BeanManager in ServletContext (the old attribute name for backwards compatibility) beanManager = (BeanManager) servletContext.getAttribute(BeanManager.class.getName()); if (beanManager != null) { LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext()); return beanManager; } } } catch (NoClassDefFoundError e) { LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindServletContextClass(), e); } catch (Exception e) { LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpServletContext(), e); } return beanManager; } public static BeanManager lookupBeanManagerCDIUtil() { BeanManager bm = null; try { bm = CDI.current().getBeanManager(); } catch (NoClassDefFoundError e) { LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindCDIClass(), e); } catch (Exception e) { LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpViaCDIUtil(), e); } return bm; } /** * Lookup ResteasyCdiExtension instance that was instantiated during CDI bootstrap * * @return ResteasyCdiExtension instance */ private ResteasyCdiExtension lookupResteasyCdiExtension() { Set<Bean<?>> beans = manager.getBeans(ResteasyCdiExtension.class); Bean<?> bean = manager.resolve(beans); if (bean == null) { throw new IllegalStateException(Messages.MESSAGES.unableToObtainResteasyCdiExtension()); } CreationalContext<?> context = manager.createCreationalContext(bean); return (ResteasyCdiExtension) manager.getReference(bean, ResteasyCdiExtension.class, context); } }